/**-----------------------------------------------
*File name: NetworkFederate.h
*Author: Tran Van Hoang
*Date: 26/03/2015
*Version: 1.0
******************/
#ifndef NETWORKFEDERATE_H_
#define NETWORKFEDERATE_H_

#include "RTI.hh"
#include "NullFederateAmbassador.hh"
#include "fedtime.hh"
#include "libhla.hh"
#include "MessageBuffer.hh"
#include "cellNetwork.h"

class NetworkFederate : public NullFederateAmbassador
{
	public:
		NetworkFederate(std::string, std::string);
		virtual ~NetworkFederate() throw (RTI::FederateInternalError);
		void runFederate(std::string federation_name);
		void waitForUser();
		void createFederation(std::string federation_name);
		void joinFederation(std::string federate_name);
		void pause();
		virtual void publishAndSubscribe();
		void setTimeRegulation(bool constrained, bool regulating);
		RTIfedTime timeAdvance(RTIfedTime time_step);
		virtual void checkRegions();
		void synchronize(int auto_start);
		void tick();
		RTI::ObjectHandle registerObject();		
		RTI::FederateHandle getHandle() const;
		double convertTime(const RTI::FedTime& theTime);
		void simulating();
		 // Callbacks
		void synchronizationPointRegistrationSucceeded(const char* label)
			throw(RTI::FederateInternalError);

		void synchronizationPointRegistrationFailed(const char* label)
			throw(RTI::FederateInternalError);

		void announceSynchronizationPoint(const char *label, const char */*tag*/)
		    throw (RTI::FederateInternalError);

		void federationSynchronized(const char *label)
			throw(RTI::FederateInternalError);

    		void timeAdvanceGrant(const RTI::FedTime& theTime)
        		throw (RTI::FederateInternalError, RTI::TimeAdvanceWasNotInProgress,
               			RTI::InvalidFederationTime);

    		void discoverObjectInstance(RTI::ObjectHandle theObject,
                                RTI::ObjectClassHandle theObjectClass,
                                const char *theObjectName)
        		throw (RTI::FederateInternalError, RTI::ObjectClassNotKnown, RTI::CouldNotDiscover);
		void reflectAttributeValues(RTI::ObjectHandle theObject,
                                const RTI::AttributeHandleValuePairSet& theAttributes,
                                const RTI::FedTime& theTime, const char *theTag,
                                RTI::EventRetractionHandle theHandle)
        		throw (RTI::ObjectNotKnown, RTI::AttributeNotKnown,
               			RTI::InvalidFederationTime, RTI::FederateInternalError);

    		void reflectAttributeValues(RTI::ObjectHandle,
                                const RTI::AttributeHandleValuePairSet &,
                                const char *)
       	 		throw (RTI::ObjectNotKnown, RTI::AttributeNotKnown,
               			RTI::FederateInternalError);

    		void receiveInteraction(RTI::InteractionClassHandle theInteraction,
                            const RTI::ParameterHandleValuePairSet& theParameters,
                            const RTI::FedTime& theTime, const char *theTag,
                            RTI::EventRetractionHandle theHandle)
        		throw (RTI::InteractionClassNotKnown, RTI::InteractionParameterNotKnown,
               			RTI::InvalidFederationTime, RTI::FederateInternalError);

    		void receiveInteraction(RTI::InteractionClassHandle,
                            const RTI::ParameterHandleValuePairSet &,
                            const char *)
        		throw (RTI::InteractionClassNotKnown, RTI::InteractionParameterNotKnown,
               			RTI::FederateInternalError);
		void removeObjectInstance(RTI::ObjectHandle theObject, const RTI::FedTime& theTime,
                              const char *theTag,
                              RTI::EventRetractionHandle theHandle)
        		throw (RTI::ObjectNotKnown, RTI::InvalidFederationTime, RTI::FederateInternalError);

    		void removeObjectInstance(RTI::ObjectHandle, const char *)
        		throw (RTI::ObjectNotKnown, RTI::FederateInternalError);


    		void sendInteraction(double, double, const RTI::FedTime &, RTI::ObjectHandle);
    		void sendInteraction(double, double, RTI::ObjectHandle);

		void sendUpdate(SensorNode *sensorNode, CellArray *cells,const RTI::FedTime & UpdateTime, RTI::ObjectHandle id, int node_number);

    		//void sendUpdate(double, double, int, const RTI::FedTime &, RTI::ObjectHandle);

    		bool getCreator(){return creator;};

	private:


		/**
    		 * Helper class to simplify string construction. Implemented as
     		* a stringstream wrapper.
     		*
     		* For example:
     		* throw AttributeNotDefined(stringize() << "value: " << number);
     		*/
    		template<typename C>
   		struct basic_stringize
    		{
      		      	template<typename T>
      		      	basic_stringize<C> & operator << (const T& t)
      		      	{
        			m_s << t;
        			return *this;
      			}

      			// note: must not return reference
      			operator const std::basic_string<C>() const
      			{
        			return m_s.str();
      			}

    			private:
      		       		std::basic_stringstream<C> m_s;
    		};

    		typedef basic_stringize<char> stringize;
    		typedef basic_stringize<wchar_t> wstringize;

	protected:
		virtual void getHandles();

		RTI::RTIambassador rtiamb;
	
		std::string federateName;
		std::string federationName;
		std::string fddName;//file name of FOM
		RTI::FederateHandle handle;
		bool creator;
		long nbTicks;
		bool joined;

		bool regulating;
		bool constrained;
		bool notimestamp;
		RTIfedTime localTime;
		const RTIfedTime TIME_STEP;

		bool paused;
		bool granted;
		bool verbose;

		// Handles		
		RTI::ObjectClassHandle		ForestNodeClassID;
		RTI::ObjectClassHandle		SensorNodeClassID;

		RTI::AttributeHandle		SensorAttrXID;
		RTI::AttributeHandle		SensorAttrYID;
		RTI::AttributeHandle		SensorAttrStateID;
		RTI::AttributeHandle		SensorAttrImageExtentXID;
		RTI::AttributeHandle		SensorAttrImageExtentYID;


		RTI::AttributeHandle		ForestAttrXID;
		RTI::AttributeHandle		ForestAttrYID;
		RTI::AttributeHandle		ForestAttrStateID;
		RTI::AttributeHandle		ForestAttrImageExtentXID;
		RTI::AttributeHandle		ForestAttrImageExtentYID;

};

#endif
